// 深拷贝是指创建一个新对象，新对象的属性值与原对象相同
// 但它们在内存中是完全独立的，修改新对象不会影响原对象，反之亦然。

// 大致分为:
// copy
// hash.set
// return copy

// 深拷贝
function deepCopy(obj, hash = new WeakMap()) {
  // 非对象或 null 直接返回
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 检查是否已拷贝过该对象（处理循环引用）
  if (hash.has(obj)) {
    return hash.get(obj);
  }

  let copy;

  // 处理日期对象
  if (obj instanceof Date) {
    copy = new Date(obj.getTime());
    hash.set(obj, copy);
    return copy;
  }

  // 处理正则表达式对象
  if (obj instanceof RegExp) {
    copy = new RegExp(obj.source, obj.flags);
    hash.set(obj, copy);
    return copy;
  }

  // 处理Map对象
  if (obj instanceof Map) {
    copy = new Map();
    hash.set(obj, copy);
    obj.forEach((value, key) => {
      // 对Map的键和值都进行深拷贝
      copy.set(deepCopy(key, hash), deepCopy(value, hash));
    });
    return copy;
  }

  // 处理Set对象
  if (obj instanceof Set) {
    copy = new Set();
    hash.set(obj, copy);
    obj.forEach(value => {
      // 对Set的值进行深拷贝
      copy.add(deepCopy(value, hash));
    });
    return copy;
  }

  // 处理Error对象
  if (obj instanceof Error) {
    copy = new Error(obj.message);
    copy.stack = obj.stack;
    copy.name = obj.name;
    hash.set(obj, copy);
    return copy;
  }

  // 处理数组
  if (Array.isArray(obj)) {
    copy = [];
    hash.set(obj, copy);
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepCopy(obj[i], hash);
    }
  }
  // 处理普通对象，使用构造函数保持原型链
  else {
    // 创建与原对象相同原型的新对象，保持原型链
    copy = Object.create(Object.getPrototypeOf(obj));
    hash.set(obj, copy);
    
    // 拷贝所有可枚举属性
    for (let key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        copy[key] = deepCopy(obj[key], hash);
      }
    }
    
    // 拷贝Symbol作为键的属性
    const symbolKeys = Object.getOwnPropertySymbols(obj);
    for (const symbolKey of symbolKeys) {
      copy[symbolKey] = deepCopy(obj[symbolKey], hash);
    }
  }

  return copy;
}